/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2008-2009, Intel Corporation.
 * All Rights Reserved.
 */

#ifndef _LATENCYTOP_H
#define	_LATENCYTOP_H

#include <sys/types.h>

#include <glib.h>

#ifdef	__cplusplus
extern "C" {
#endif

/*
 * Without this lint seems to be confused by glib header file.
 */
#ifdef __lint
#undef g_assert
#define	g_assert(x)	((void)(x))
#undef TRUE
#define	TRUE		1
#endif

/*
 * We define our own conversions in order to avoid compiler warnings.
 */
#define	LT_INT_TO_POINTER(a)	((void *)(unsigned long)(a))

#define	TITLE			"LatencyTOP for OpenSolaris, version 1.0"
#define	COPYRIGHT		"Copyright (c) 2008-2009, Intel Corporation."
#define	DEFAULT_KLOG_FILE	"/var/log/latencytop.log"

#define	INVALID_PID		(~0)
#define	INVALID_TID		(~0)
#define	PID_SYS_GLOBAL		INVALID_PID
#define	INVALID_CAUSE		0
#define	HIGHER_PRIORITY(a, b)	((a) > (b))

#ifdef EMBED_CONFIGS
/*
 * LatencyTOP configuration is embedded in the binary.
 * Array will be generated by elfwrap.
 */
extern char latencytop_d_start;
extern char latencytop_d_end;
extern char latencytop_trans_start;
extern char latencytop_trans_end;
#else
/*
 * LatencyTOP configuration is provided externally by user.
 */
#define	DEFAULT_CONFIG_NAME	"./latencytop.trans"
#define	DEFAULT_D_SCRIPT_NAME   "./latencytop.d"
#endif

typedef enum {
	LT_STAT_COUNT,
	LT_STAT_MAX,
	LT_STAT_SUM,
} lt_stat_type_t;

#define	LT_KLOG_LEVEL_NONE	0	/* Log nothing */
#define	LT_KLOG_LEVEL_UNMAPPED	1	/* Log only stacks not mapped */
#define	LT_KLOG_LEVEL_MAPPED	2	/* Log only stacks mapped */
#define	LT_KLOG_LEVEL_ALL	3	/* Log all stacks, mapped or not */

typedef enum {
	LT_LEVEL_GLOBAL,	/* System wide statistics */
	LT_LEVEL_PROCESS,	/* Per-process statistics */
	LT_LEVEL_THREAD,	/* Per-thread statistics */
} lt_stat_level_t;

typedef enum {
	LT_SORT_TOTAL,
	LT_SORT_MAX,
	LT_SORT_AVG,
	LT_SORT_COUNT,
} lt_sort_t;

typedef enum {
	LT_FIELD_FNAME,
	LT_FIELD_PSARGS,
} lt_field_t;

typedef enum {
	LT_LIST_CAUSE,		/* List latency by causes (default) */
	LT_LIST_SPECIALS,	/* List only "special" causes */
	LT_LIST_SOBJ		/* List synchronization objects */
} lt_list_type_t;

/*
 * Data structure which contains statistics.
 */
typedef struct {
	uint64_t lt_s_count;
	uint64_t lt_s_total;
	uint64_t lt_s_max;
} lt_stat_data_t;

/*
 * Data structure that stores statistics along with the name.
 */
typedef struct {
	enum {
		STAT_CAUSE,
		STAT_SOBJ
	} lt_se_type;
	const char *lt_se_string;
	lt_stat_data_t lt_se_data;
	union {
		struct {
			int lt_se_c_id;
			int lt_se_c_flags;
		} lt_se_t_cause;
		struct {
			int lt_se_s_id;
		} lt_se_t_sobj;
	} lt_se_tsdata;	/* type specific data */
} lt_stat_entry_t;

typedef struct {
	int lt_cfg_enable_filter;
	int lt_cfg_trace_sched;
	int lt_cfg_trace_syncobj;
	int lt_cfg_low_overhead_mode;
	int lt_cfg_snap_interval;
	char *lt_cfg_config_name;
	unsigned int lt_cfg_trace_pid;
	unsigned int lt_cfg_trace_pgid;
} lt_config_t;

extern lt_config_t g_config;	/* The global settings */

/*
 * Causes can be disabled through the configuration file.
 * When disabled, though D script will continue to capture causes, they will
 * not be counted by LatencyTOP.
 */
#define	CAUSE_FLAG_DISABLED		1
/*
 * This flag will not show and count causes as part of summary in
 * "kstack window".
 */
#define	CAUSE_FLAG_HIDE_IN_SUMMARY	2
/*
 * This is generated from D script (named cause), and is "special".
 */
#define	CAUSE_FLAG_SPECIAL		4
#define	CAUSE_ALL_FLAGS			0xffffffff

extern boolean_t lt_drop_detected;

/*
 * These functions collect statistics using DTrace.
 */
extern int lt_dtrace_init(void);
extern int lt_dtrace_work(int);
extern int lt_dtrace_collect(void);
extern int lt_dtrace_deinit(void);

/*
 * These functions maintain configuration, e.g. symbol to cause mapping.
 */
extern int lt_table_init(void);
extern int lt_table_cause_from_stack(const char *, int *, int *);
extern const char *lt_table_get_cause_name(int);
extern int lt_table_get_cause_flag(int, int);
extern int lt_table_cause_from_name(char *, int, int);
extern int lt_table_append_trans(FILE *fp);
extern void lt_table_deinit(void);

/*
 * These functions update statistic of all causes of latency, collected
 * from DTrace.
 */
extern void lt_stat_update(pid_t, id_t, char *, char *, unsigned int,
    lt_stat_type_t, uint64_t);
extern void lt_stat_update_cause(pid_t, id_t, int, lt_stat_type_t, uint64_t);
extern void lt_stat_update_sobj(pid_t, id_t, int, unsigned long long,
    lt_stat_type_t, uint64_t);
extern void lt_stat_clear_all(void);
extern void lt_stat_free_all(void);

/*
 * These functions produce lists for display panes.
 * Note: after a call to lt_stat_update_*, the old lists will become invalid.
 */
extern void *lt_stat_list_create(lt_list_type_t, lt_stat_level_t,
    pid_t, id_t, int, lt_sort_t);
extern int lt_stat_list_has_item(void *, int);
extern const char *lt_stat_list_get_reason(void *, int);
extern uint64_t lt_stat_list_get_max(void *, int);
extern uint64_t lt_stat_list_get_sum(void *, int);
extern uint64_t lt_stat_list_get_count(void *, int);
extern uint64_t lt_stat_list_get_gtotal(void *);
extern void lt_stat_list_free(void *);

/*
 * These functions produce the process list and the thread list.
 */
extern int lt_stat_proc_list_create(pid_t **, id_t **);
extern void lt_stat_proc_list_free(pid_t *, id_t *);
extern const char *lt_stat_proc_get_name(pid_t);
extern int lt_stat_proc_get_nthreads(pid_t);

/*
 * These functions use ncurses to create console-based display.
 */
extern void lt_display_init(void);
extern int lt_display_loop(int);
extern void lt_display_error(const char *, ...);
extern void lt_display_deinit(void);

/*
 * Write statistics to log file - useful for debugging and offline analysis.
 */
extern void lt_klog_init(void);
extern void lt_klog_deinit(void);
extern int lt_klog_set_log_file(const char *);
extern int lt_klog_set_log_level(int);
extern void lt_klog_write(void);
extern void lt_klog_log(int, pid_t, char *, lt_stat_type_t,
    uint64_t);

/*
 * Utility functions.
 */
extern uint64_t lt_millisecond(void);
extern void *lt_malloc(size_t);
extern void *lt_zalloc(size_t);
extern char *lt_strdup(const char *);
extern void lt_check_null(void *);
extern void lt_time_str(char *, int);
extern char *lt_get_proc_field(pid_t, lt_field_t);
extern void lt_update_stat_value(lt_stat_data_t *, lt_stat_type_t, uint64_t);
extern int lt_sort_by_total_desc(lt_stat_entry_t *, lt_stat_entry_t *);
extern int lt_sort_by_max_desc(lt_stat_entry_t *, lt_stat_entry_t *);
extern int lt_sort_by_count_desc(lt_stat_entry_t *, lt_stat_entry_t *);
extern int lt_sort_by_avg_desc(lt_stat_entry_t *, lt_stat_entry_t *);
extern void lt_gpipe_init(void);
extern void lt_gpipe_deinit(void);
extern void lt_gpipe_break(const char *);
extern int lt_gpipe_readfd(void);
extern int lt_file_exist(const char *);

#ifdef	__cplusplus
}
#endif

#endif	/* _LATENCYTOP_H */
